#include "serialporttestwgt.h"
#include "ui_serialporttestwgt.h"
#include <QDebug>
#include <QTimer>
#include <QThread>
#include <QSettings>
#include <QMessageBox>
#include <QSerialPort>
#include <QSerialPortInfo>

uint16_t crc16(unsigned char *recv_buf,uint16_t length)
{
    uint16_t crc_sum = 0xFFFF;
    int i, j;

    for (i = 0; i < length; i++)
    {
        crc_sum = crc_sum^((uint16_t)recv_buf[i]);
        for (j = 0; j < 8; j++)
        {
            if (crc_sum & 0x0001)
            {
                crc_sum = crc_sum >> 1;
                crc_sum = crc_sum^0xA001;
            }
            else
            {
                crc_sum = crc_sum >> 1;
            }
        }
    }

    return crc_sum;
}

SerialPortTestWgt::SerialPortTestWgt(QWidget *parent)
    : QWidget(parent),m_isReplay(false),m_pScanTimer(nullptr)
    , m_pReadTimer(nullptr), m_pWaitTimer(nullptr)
    , ui(new Ui::SerialPortTestWgt),m_timeDuration(0)
{
    ui->setupUi(this);

    setWindowTitle(tr("SerialPortTestTool"));
    setContrlVisible(false);
    read_ini_file();

    m_port = new QSerialPort;
    connect(m_port,SIGNAL(readyRead()),this,SLOT(sltReadData()));
    m_pReadTimer = new QTimer(this);
    m_pReadTimer->setTimerType(Qt::PreciseTimer);
    connect(m_pReadTimer, SIGNAL(timeout()), this, SLOT(sltTimeUpdate()));

    m_pScanTimer = new QTimer(this);
    connect(m_pScanTimer, &QTimer::timeout, this, &SerialPortTestWgt::sltScanSerialPort);
    m_pScanTimer->setTimerType(Qt::PreciseTimer);
    m_pScanTimer->start(5000);

    m_pWaitTimer = new QTimer(this);
    m_pWaitTimer->setTimerType(Qt::PreciseTimer);
    connect(m_pWaitTimer, &QTimer::timeout, this, &SerialPortTestWgt::sltWaitReplay);
}

SerialPortTestWgt::~SerialPortTestWgt()
{
    if(m_pScanTimer->isActive())
    {
        m_pScanTimer->stop();
        delete m_pScanTimer;
        m_pScanTimer = nullptr;
    }

    if(m_pReadTimer->isActive())
    {
        m_pReadTimer->stop();
        delete m_pReadTimer;
        m_pReadTimer = nullptr;
    }

    if(m_pWaitTimer->isActive())
    {
        m_pWaitTimer->stop();
        delete m_pWaitTimer;
        m_pWaitTimer = nullptr;
    }

    delete ui;
}

void SerialPortTestWgt::sltScanSerialPort()
{
    if(m_port->isOpen())
    {
        //状态正常
        if (m_port->error() == QSerialPort::NoError)
        {
            return;
        }
        on_openSerialPort_clicked();
    }

    ui->cbx_portSelect->clear();
    foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
    {
        //这里只是临时读取可用串口不要在堆区直接开辟空间
        QSerialPort port;
        port.setPort(info);

        //以可读可写的方式打开(临时打开，扫描可用串口)
        if(port.open(QIODevice::ReadWrite))
        {
            //将扫描到的可用串口写入到comboBox里
            ui->cbx_portSelect->addItem(port.portName());

            //关闭串口
            port.close();
            QCoreApplication::processEvents();
        }
    }
}

void SerialPortTestWgt::read_ini_file()
{
    m_algorithmValue.clear();
    QString strPath = QApplication::applicationDirPath() + "/setting.ini";
    QSettings settings(strPath, QSettings::IniFormat);
    int size = settings.beginReadArray("AlgorithmType");
    for (int i = 0; i < size; ++i)
    {
       settings.setArrayIndex(i);

       QString algoName = settings.value("name").toString();
       m_algorithmValue.insert(algoName,settings.value("value").toUInt());

       //更新到界面算法选项框
       ui->cbx_algorSelect->addItem(algoName);
    }
    settings.endArray();

    size = settings.beginReadArray("TargetType");
    for (int i = 0; i < size; ++i)
    {
       settings.setArrayIndex(i);

       quint32 enumv = settings.value("enum").toUInt();
       m_targetTypeValue.insert(enumv,settings.value("value").toString());
    }
    settings.endArray();

    m_timeDuration = settings.value("durationSet").toUInt();
}

void SerialPortTestWgt::setContrlVisible(bool bVisible)
{
    ui->spb_depthValue->setVisible(bVisible);
    ui->label_depthValue->setVisible(bVisible);
    ui->label_depthValue->clear();
}

void SerialPortTestWgt::on_openSerialPort_clicked()
{
    if(!m_port->isOpen())
    {
        setContrlVisible(false);
        m_port->setBaudRate(QSerialPort::Baud115200); //设置波特率
        m_port->setPortName(ui->cbx_portSelect->currentText());
        if(m_port->open(QIODevice::ReadWrite))
        {
            m_port->setDataBits(QSerialPort::Data8);  //设置数据位
            m_port->setStopBits(QSerialPort::OneStop);//设置停止位
            m_port->setParity(QSerialPort::NoParity); //设置奇偶校验
            m_port->setFlowControl(QSerialPort::NoFlowControl);//设置流控制
            m_port->setReadBufferSize(40960);//设置缓存
            ui->openSerialPort->setText("关闭串口");
        }
        else
        {
            QMessageBox::warning(this,"提示",QString("串口打开失败!"));
            qDebug() << "串口打开失败!" << endl;
        }
    }
    else
    {
        m_port->close();
        ui->openSerialPort->setText("打开串口");
    }
}

void SerialPortTestWgt::on_startBtn_clicked()
{
    if(!m_port->isOpen())
    {
        QMessageBox::warning(this,"提示",QString("串口未打开!!!"));
        return;
    }

    QByteArray sndData;
    sndData.append(0x7E);
    sndData.append(0xFF);
    sndData.append(0x17);
    sndData.append(0x02);
    int algType = m_algorithmValue[ui->cbx_algorSelect->currentText()];
    sndData.append((uint8_t)algType);
    if(ui->cbx_algorSelect->currentIndex() == 0)//0默认是声算法
    {
        sndData.append((uint8_t)0x00);
    }
    else
    {
        double depthValue = ui->spb_depthValue->value();
        sndData.append((uint8_t)depthValue);
    }
    //计算校验位 低8位在前，高8位在后
    uint16_t value = crc16((unsigned char *)sndData.data(),6);
    uint8_t low =  (uint8_t)(value & 0xFF);// 取低8位
    uint8_t high =  (uint8_t)(value >> 8); // 取高8位
    sndData.append(low);
    sndData.append(high);

    //写入发送缓存区
    m_port->write(sndData);

    //更新到界面发送区
    QString strDisplay = "start cmd：";
    QString str = sndData.toHex().data();
    str = str.toUpper();
    for(int i=0;i<str.length();i+=2)
    {
        QString st = str.mid(i,2);
        strDisplay += st;
        strDisplay += " ";
    }
    ui->textBrowser_send->append(strDisplay);

//    shotTest();
//    return;

    ui->textBrowser_recv->append(tr("识别中..."));

    if(m_pWaitTimer->isActive())
    {
        m_pWaitTimer->stop();
    }
    m_pWaitTimer->start(1000 * m_timeDuration);

    m_isReplay = false;
}

void SerialPortTestWgt::on_resetBtn_clicked()
{
    if(!m_port->isOpen())
    {
        QMessageBox::warning(this,"提示",QString("串口未打开!!!"));
        return;
    }

    if(m_pWaitTimer->isActive())
    {
        m_pWaitTimer->stop();
    }

    QByteArray sndData;
    sndData.append(0x7E);
    sndData.append(0xFF);
    sndData.append(0xA1);
    sndData.append((uint8_t)0x00);

    //计算校验位 低8位在前，高8位在后
    uint16_t value = crc16((unsigned char *)sndData.data(),4);
    uint8_t low =  (uint8_t)(value & 0xFF);// 取低8位
    uint8_t high =  (uint8_t)(value >> 8); // 取高8位
    sndData.append(low);
    sndData.append(high);

    // 写入发送缓存区
    m_port->write(sndData);

    //更新到界面发送区
    QString strDisplay = "reset cmd：";
    QString str = sndData.toHex().data();
    str = str.toUpper();
    for(int i=0;i<str.length();i+=2)
    {
        QString st = str.mid(i,2);
        strDisplay += st;
        strDisplay += " ";
    }
    ui->textBrowser_send->append(strDisplay);
}

void SerialPortTestWgt::sltReadData()
{
    m_pReadTimer->start(100);//启动定时器，接收100毫秒数据（根据情况设定）
    m_rcvbuff.append(m_port->readAll());
}

void SerialPortTestWgt::sltWaitReplay()
{
    m_pWaitTimer->stop();

    if(m_isReplay == false)
    {
        //到达设置时间后，仍未收到回复界面显示信息
        ui->textBrowser_recv->append(tr("不动作"));
    }
}

void SerialPortTestWgt::sltTimeUpdate()
{
    m_pReadTimer->stop();

    if(m_rcvbuff.length()!= 0)
    {
        //将数据转换成16进制
        if(m_rcvbuff.size() == 10)
        {
            //uint8_t flag = rcvData[4];//1:success;0:fail
            uint8_t low = m_rcvbuff[5];  //low
            uint8_t high = m_rcvbuff[6]; //high
            uint16_t triggerTime = high;
            triggerTime = (triggerTime << 8) | low;

            QString strResult = tr("决策时间:%1秒").arg(QString::number(triggerTime));
            strResult.append(",");
            if(ui->cbx_algorSelect->currentText().contains("Sweep"))
            {
                uint8_t targetType = m_rcvbuff[7];
                QString strTargetType = tr("目标类别:%1").arg(m_targetTypeValue[targetType]);
                strResult.append(strTargetType);

                if(strTargetType.contains("ship"))
                {
                    strResult.append(",动作");
                }
                else
                {
                    strResult.append(",不动作");
                }
            }
            else
            {
                strResult.append(",动作");
            }

            ui->textBrowser_recv->append(strResult);
            m_isReplay = true;
        }

        //接收指令更新到接收区
//        QString strDisplay = "recv cmd：";
//        QString str = m_rcvbuff.toHex();
//        str = str.toUpper();
//        for(int i=0; i<str.length(); i+=2)
//        {
//            QString st = str.mid(i,2);
//            strDisplay += st;
//            strDisplay += " ";
//        }
    }
    m_rcvbuff.clear();
}

void SerialPortTestWgt::on_sendClearBtn_clicked()
{
    ui->textBrowser_send->clear();
}

void SerialPortTestWgt::on_recvClearBtn_clicked()
{
    ui->textBrowser_recv->clear();
}

void SerialPortTestWgt::on_cbx_algorSelect_currentIndexChanged(const QString &name)
{
    if(name.contains("Sweep")) //磁算法
    {
        setContrlVisible(true);
    }
    else
    {
        setContrlVisible(false);
    }
}

void SerialPortTestWgt::shotTest()
{
    QHash<QString ,quint32> imageValue;
    QString strPath = QApplication::applicationDirPath() + "/setting.ini";
    QSettings settings(strPath, QSettings::IniFormat);
    int size = settings.beginReadArray("ShootSet");
    for (int i = 0; i < size; ++i)
    {
       settings.setArrayIndex(i);

       QString name = settings.value("name").toString();
       imageValue.insert(name,settings.value("time").toUInt());

    }
    settings.endArray();

    QThread::sleep(5000);

    for (auto iter = imageValue.begin(); iter != imageValue.end(); ++iter)
    {
        quint32 time = iter.value();

        QString strResult = tr("决策时间:%1秒").arg(QString::number(time));
        strResult.append(",");
        strResult.append(",动作");

        ui->textBrowser_recv->clear();
        ui->textBrowser_recv->append(strResult);

        // 截取QWidget的屏幕部分
        QPixmap originalPixmap = QPixmap::grabWidget(this);

        // 将QPixmap转换为QImage，以便保存
        QImage image = originalPixmap.toImage();

        // 保存图片到文件
        QString imgName = iter.key() + ".png";
        image.save(imgName);

        QThread::sleep(1000);
    }
}
